package com.sun.audit.resolver;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.mapping.MappedStatement;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;

@Slf4j
public class EntityClassResolver {
    public static Class<?> resolve(MappedStatement ms, Object parameter) {

        // 1. 从 MappedStatement 获取实体类类型
        Class<?> entityClass = getEntityClassFromMappedStatement(ms);
        if (entityClass != null) {
            log.info("通过 MappedStatement 获取实体类: {}", entityClass.getName());
            return entityClass;
        }

        // 2. 从参数对象获取实体类
        if (parameter != null) {
            Class<?> paramClass = getEntityClassFromParameter(parameter);
            if (paramClass != null) {
                log.info("通过参数对象获取实体类: {}", paramClass.getName());
                return paramClass;
            }
        }
        return null;
    }

    /**
     * 方法 1：通过 MappedStatement 获取实体类
     */
    private static Class<?> getEntityClassFromMappedStatement(MappedStatement ms) {
        try {
            // 1.1 从 SQL ID 解析 Mapper 接口类
            String mapperClassName = ms.getId().substring(0, ms.getId().lastIndexOf("."));
            Class<?> mapperClass = Class.forName(mapperClassName);

            // 1.2 获取 Mapper 接口的泛型参数 (实体类类型)
            return extractEntityClassFromMapper(mapperClass);
        } catch (Exception e) {
            log.error("通过 MappedStatement 获取实体类失败", e);
            return null;
        }
    }

    /**
     * 从 Mapper 接口提取实体类
     */
    private static Class<?> extractEntityClassFromMapper(Class<?> mapperClass) {
        // 获取所有实现的接口
        for (Type genericInterface : mapperClass.getGenericInterfaces()) {
            if (genericInterface instanceof ParameterizedType) {
                ParameterizedType pt = (ParameterizedType) genericInterface;

                // 检查是否是 BaseMapper 的子类
                if (pt.getRawType() instanceof Class &&
                        BaseMapper.class.isAssignableFrom((Class<?>) pt.getRawType())) {

                    // 获取第一个泛型参数 (实体类类型)
                    Type[] actualTypeArguments = pt.getActualTypeArguments();
                    if (actualTypeArguments.length > 0 && actualTypeArguments[0] instanceof Class) {
                        return (Class<?>) actualTypeArguments[0];
                    }
                }
            }
        }
        return null;
    }

    /**
     * 方法 2：从参数对象获取实体类
     */
    private static Class<?> getEntityClassFromParameter(Object parameter) {
        // 2.1 如果参数是实体类对象
        if (isEntity(parameter)) {
            return parameter.getClass();
        }
        // 2.2 如果参数是 Map (MyBatis 参数封装)
        if (parameter instanceof Map) {
            Map<?, ?> paramMap = (Map<?, ?>) parameter;
            // 尝试从 Map 中获取实体类对象
            for (Object value : paramMap.values()) {
                if (isEntity(value)) {
                    return value.getClass();
                }
            }
            // 2.3 特殊处理：MyBatis-Plus 的 Wrapper 参数
            for (Object value : paramMap.values()) {
                if (value instanceof Wrapper) {
                    return getEntityClassFromWrapper((Wrapper<?>) value);
                }
            }
        }
        return null;
    }

    /**
     * 判断对象是否是实体类
     */
    private static boolean isEntity(Object obj) {
        if (obj == null) {
            return false;
        }
        Class<?> clazz = obj.getClass();
        // 简单判断标准：有 @TableName 注解 (MyBatis-Plus 实体类标志)
        return clazz.isAnnotationPresent(TableName.class);
    }

    /**
     * 从 Wrapper 获取实体类
     */
    private static Class<?> getEntityClassFromWrapper(Wrapper<?> wrapper) {
        try {
            // 使用反射获取 Wrapper 中的 entityClass 字段
            Field entityClassField = Wrapper.class.getDeclaredField("entityClass");
            entityClassField.setAccessible(true);
            return (Class<?>) entityClassField.get(wrapper);
        } catch (Exception e) {
            log.warn("从 Wrapper 获取实体类失败", e);
            return null;
        }
    }


    private static TableInfo getTableInfo(MappedStatement ms) {
        try {
            String modelName = ms.getId().substring(0, ms.getId().lastIndexOf("."));
            Class<?> modelClass = Class.forName(modelName);
            return TableInfoHelper.getTableInfo(modelClass);
        } catch (Exception e) {
            return null;
        }
    }
}
